package aceim.protocol.snuk182.mrim.inner;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.DefaultHttpClient;
import aceim.protocol.snuk182.mrim.MrimEntityAdapter;
import aceim.protocol.snuk182.mrim.inner.dataentity.MrimBosString;
import aceim.protocol.snuk182.mrim.inner.dataentity.MrimBuddy;
import aceim.protocol.snuk182.mrim.inner.dataentity.MrimGroup;
import aceim.protocol.snuk182.mrim.inner.dataentity.MrimMessage;
import aceim.protocol.snuk182.mrim.inner.dataentity.MrimOnlineInfo;
import aceim.protocol.snuk182.mrim.inner.dataentity.MrimPacket;
import aceim.protocol.snuk182.mrim.utils.Base64;
import aceim.protocol.snuk182.mrim.utils.MD5;
import aceim.protocol.snuk182.mrim.utils.ProtocolUtils;
import android.annotation.SuppressLint;
import android.os.Build;
public final class MrimProcessor {
private Map<Long, MessageData> msgIDs = new HashMap<Long, MessageData>();
private static final String ALIAS = "Asia IM Android";
private static final String VERSION_INFO = "client=\"android\" version=\"2.0 (build 211)\" desc=\"Android Agent\"";
//private static final String VERSION_INFO = "client=\"magent\" version=\"5.8\" build=\"4139\"";
private static final String LANG = "ru";
private static final String GEO_LIST = "geo-list";
private static final String ICON_SERVER = "http://obraz.foto.mail.ru/%s/%s/_mrimavatar";
private MrimServiceInternal service;
public MrimProcessor(MrimServiceInternal service) {
this.service = service;
}
public MrimPacket parsePacket(byte[] tail) throws MrimException {
if (tail == null || tail.length < 4) {
throw new MrimException("No packet data");
}
int start4bytes = ProtocolUtils.bytes2IntLE(tail, 0);
if (start4bytes != MrimConstants.CS_MAGIC) {
return parseBosString(tail);
}
if (tail.length < 44) {
throw new MrimException("No packet data");
}
MrimPacket packet = new MrimPacket();
// first 8 bytes are useless
packet.seqNumber = ProtocolUtils.bytes2IntLE(tail, 8);
packet.type = ProtocolUtils.bytes2IntLE(tail, 12);
packet.rawData = tail;
return packet;
}
public void parsePacketTail(MrimPacket packet) {
// TODO remove
//service.log("packet " + packet.type);
if (packet.type == MrimConstants.MRIM_CS_HELLO) {
service.log("server hello");
reconnectBos((MrimBosString) packet);
return;
}
switch (packet.type) {
case MrimConstants.MRIM_CS_MPOP_SESSION:
service.getServiceResponse().respond(MrimServiceResponse.RES_KEEPALIVE);
break;
case MrimConstants.MRIM_CS_HELLO_ACK:
parsePingFreq(packet);
//proceedLogin();
try {
proceedLogin3();
} catch (IOException e) {
service.log(e);
}
break;
case MrimConstants.MRIM_CS_LOGIN_ACK:
service.log("login ok");
service.getServiceResponse().respond(MrimServiceResponse.RES_CONNECTING, 5);
break;
case MrimConstants.MRIM_CS_LOGIN_REJ:
service.log("login failed");
loginFailed(packet);
break;
case MrimConstants.MRIM_CS_LOGOUT:
parseLogout(packet);
break;
case MrimConstants.MRIM_CS_CONTACT_LIST2:
service.getServiceResponse().respond(MrimServiceResponse.RES_CONNECTING, 7);
service.log("contact list");
parseContacts(packet);
setStatus(service.getOnlineInfo());
break;
case MrimConstants.MRIM_CS_MESSAGE_ACK:
parseMessage(packet);
break;
case MrimConstants.MRIM_CS_MESSAGE_STATUS:
parseMessageAck(packet);
break;
case MrimConstants.MRIM_CS_USER_STATUS:
parseUserStatus(packet);
break;
case MrimConstants.MRIM_CS_CONNECTION_PARAMS:
parsePingFreq(packet);
break;
case MrimConstants.MRIM_CS_NEW_EMAIL:
parseNewEmail(packet);
break;
case MrimConstants.MRIM_CS_MAILBOX_STATUS:
parseMailboxStatus(packet);
break;
case MrimConstants.MRIM_CS_OFFLINE_MESSAGE_ACK:
parseOfflineMessage(packet);
break;
case MrimConstants.MRIM_CS_USER_INFO:
service.log("my own info");
break;
case 0x1079:
service.log("some 1079 received");
break;
case MrimConstants.MRIM_CS_FILE_TRANSFER:
service.getFileTransferEngine().parseFTRequest(packet);
break;
case MrimConstants.MRIM_CS_FILE_TRANSFER_ACK:
service.getFileTransferEngine().parseFTResponse(packet);
break;
case MrimConstants.MRIM_CS_PROXY:
service.getFileTransferEngine().parseFTProxyConnectionRequest(packet);
break;
case MrimConstants.MRIM_CS_PROXY_ACK:
service.getFileTransferEngine().parseFTProxyAck(packet);
break;
}
return;
}
private void parseOfflineMessage(MrimPacket packet) {
int pos = 44;
byte[] idBytes = new byte[4];
System.arraycopy(packet.rawData, pos, idBytes, 0, 4);
int id = ProtocolUtils.bytes2IntLE(idBytes);
pos+=4;
try {
String email = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
service.log("Email \n" + email);
String date = getMailValue(email, "Date");
String from = getMailValue(email, "From");
String msg = getMailMessage(email);
long flags = 0;
try {
flags = Integer.parseInt(getMailValue(email, "X-MRIM-Flags"), 16);
} catch (Exception e) {
}
service.log("offline "+from+"/"+date+"/"+msg+"/"+flags);
final MrimMessage message = new MrimMessage();
message.text = msg+" \r\n"+date;
message.from = from;
message.messageId = id;
if (message.from != null && message.from.length() > 0) {
new Thread(){
@Override
public void run(){
service.getServiceResponse().respond(MrimServiceResponse.RES_MESSAGE, message);
}
}.start();
}
//sendDeleteOfflineMsgRequest(idBytes);
/*if ((service.getOnlineInfo().status & MrimConstants.STATUS_FLAG_INVISIBLE) == 0 && (flags & MrimConstants.MESSAGE_FLAG_NORECV) == 0){
sendMsgAck(from, id);
}*/
} catch (Exception e) {
service.log(e);
}
}
@SuppressWarnings("unused")
private void sendDeleteOfflineMsgRequest(byte[] idBytes) {
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_DELETE_OFFLINE_MESSAGE;
packet.rawData = idBytes;
service.getRunnableService().sendToSocket(packet);
}
@SuppressLint("DefaultLocale")
private String getMailValue(String header, String key) {
int pos = header.toLowerCase().indexOf(key.toLowerCase());
if (-1 == pos) {
return "";
}
int end = header.indexOf('\n', pos);
return header.substring(pos + key.length() + 1, end).trim();
}
private String getMailMessage(String mail) {
String body = "";
if (-1 != getMailValue(mail, "Content-Type").indexOf("multipart/")) {
String boundary = getMailValue(mail, "Boundary");
int start = mail.indexOf("--" + boundary) + 2 + boundary.length();
int end = mail.indexOf("--" + boundary, start)-1;
body = getMailBody(mail.substring(start, end));
}
if (-1 != getMailValue(mail, "Content-Transfer-Encoding").indexOf("base64")) {
byte[] data;
try {
data = Base64.decode(body);
body = ProtocolUtils.getEncodedString(data, "UTF-16LE");
} catch (IOException e) {
service.log(e);
}
}
return body;
}
private String getMailBody(String string) {
if (string.indexOf("\n\n")>-1){
return string.split("\n\n")[1];
} else {
return string.split("\r\n\r\n")[1];
}
}
private void parseMailboxStatus(MrimPacket packet) {
int pos = 44;
long emailCount = MrimEntityAdapter.ul2Long(packet.rawData, pos);
pos+=4;
StringBuilder sb = new StringBuilder();
sb.append(emailCount);
sb.append(" emails");
service.getServiceResponse().respond(MrimServiceResponse.RES_NOTIFICATION, sb.toString(), true);
}
private void parseNewEmail(MrimPacket packet) {
int pos = 44;
long emailCount = MrimEntityAdapter.ul2Long(packet.rawData, pos);
pos+=4;
String sender = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos+=(4+MrimEntityAdapter.ul2Long(packet.rawData, pos));
String topic = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
StringBuilder sb = new StringBuilder();
sb.append(emailCount);
sb.append(" emails\n\n");
sb.append(sender);
sb.append("\n");
sb.append(topic);
service.getServiceResponse().respond(MrimServiceResponse.RES_NOTIFICATION, sb.toString(), true);
}
private void parseLogout(MrimPacket packet) {
int pos = 44;
int status = ProtocolUtils.bytes2IntLE(packet.rawData, pos);
pos+=4;
if ((status & MrimConstants.LOGOUT_NO_RELOGIN_FLAG)!=0){
service.lastConnectionError = "multiple login";
} else {
service.lastConnectionError = "server disconnected - "+status;
}
service.getRunnableService().disconnect();
}
private void parseUserStatus(MrimPacket packet) {
int pos = 44;
int status = ProtocolUtils.bytes2IntLE(packet.rawData, pos);
pos+=4;
String statusName = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos+=4+statusName.length();
String xstatusname = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos+=4+(xstatusname.length()*2);
String xstatustext = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos+=4+(xstatustext.length()*2);
String email = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos+=4+email.length();
MrimOnlineInfo info = new MrimOnlineInfo();
info.status = status;
info.uin = email;
info.xstatusId = statusName;
info.xstatusName = xstatusname;
info.xstatusText = xstatustext;
service.log("uid "+email+" status "+status+" / "+statusName+" / "+xstatusname+" / "+xstatustext+" / "+new String(packet.rawData, pos, packet.rawData.length-pos-1));
service.getServiceResponse().respond(MrimServiceResponse.RES_BUDDYSTATECHANGED, info);
}
private void parseMessageAck(MrimPacket packet) {
int pos = 44;
int status = ProtocolUtils.bytes2IntLE(packet.rawData, pos);
MessageData data = msgIDs.remove(packet.seqNumber);
if (data != null){
if (status == MrimConstants.MESSAGE_DELIVERED){
service.getServiceResponse().respond(MrimServiceResponse.RES_MESSAGEACK, data.email, (long)data.id, 2);
} else {
service.getServiceResponse().respond(MrimServiceResponse.RES_MESSAGEACK, data.email, (long)data.id, 1);
}
}
}
@SuppressWarnings("unused")
private void parseMessage(MrimPacket packet) {
int pos = 44;
int msgId = ProtocolUtils.bytes2IntLE(packet.rawData, pos);
pos+=4;
int flags = ProtocolUtils.bytes2IntLE(packet.rawData, pos);
pos+=4;
String from = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos+=4+from.length();
if (((MrimConstants.MESSAGE_FLAG_NOTIFY & flags) != 0)){
service.getServiceResponse().respond(MrimServiceResponse.RES_TYPING, from);
return;
}
String text = null;
if (((MrimConstants.MESSAGE_FLAG_OLD & flags) != 0) || ((MrimConstants.MESSAGE_FLAG_AUTHORIZE & flags) != 0)){
text = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos+=4+text.length();
} else {
text = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos+=4+(text.length()*2);
}
String rtfText = null;
if (((MrimConstants.MESSAGE_FLAG_OLD & flags) != 0) || ((MrimConstants.MESSAGE_FLAG_AUTHORIZE & flags) != 0)){
rtfText = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos+=4+text.length();
} else {
rtfText = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos+=4+(text.length()*2);
}
String from2 = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos+=4+from2.length();
int seq = ProtocolUtils.bytes2IntLE(packet.rawData, pos);
pos+=4;
service.log("message from "+from+" - "+text);
MrimMessage message = new MrimMessage();
message.text = text;
message.from = from;
message.messageId = msgId;
service.getServiceResponse().respond(MrimServiceResponse.RES_MESSAGE, message);
if ((service.getOnlineInfo().status & MrimConstants.STATUS_FLAG_INVISIBLE) == 0 && (flags & MrimConstants.MESSAGE_FLAG_NORECV) == 0){
sendMsgAck(from, msgId);
}
}
private void sendMsgAck(String to, int msgId) {
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_MESSAGE_RECV;
byte[] toBytes = MrimEntityAdapter.string2lpsa(to);
byte[] msgIdBytes = ProtocolUtils.int2ByteLE(msgId);
packet.rawData = new byte[toBytes.length+msgIdBytes.length];
System.arraycopy(toBytes, 0, packet.rawData, 0, toBytes.length);
System.arraycopy(msgIdBytes, 0, packet.rawData, toBytes.length, 4);
service.getRunnableService().sendToSocket(packet);
}
private void parseContacts(MrimPacket packet) {
int pos = 44;
List<MrimGroup> groups = new ArrayList<MrimGroup>();
List<MrimBuddy> buddies = new ArrayList<MrimBuddy>();
int responseCode = (int) MrimEntityAdapter.ul2Long(packet.rawData, pos);
pos += 4;
if (responseCode != MrimConstants.GET_CONTACTS_OK){
return;
}
int groupCount = (int) MrimEntityAdapter.ul2Long(packet.rawData, pos);
pos += 4;
String groupMask = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos += (4 + groupMask.length());
String contactMask = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos += (4 + contactMask.length());
service.log("group mask " + groupMask);
service.log("contact mask " + contactMask);
for (int i = 0; i< groupCount; i++){
int flags = (int) MrimEntityAdapter.ul2Long(packet.rawData, pos);
pos += 4;
String name = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos += (4 + name.length()*2);
service.log("group name " + name+", group flags " + flags);
pos += MrimEntityAdapter.skipFormatted(packet.rawData, groupMask, pos, 2);
if ((flags & MrimConstants.CONTACT_FLAG_REMOVED) != 0){
continue;
}
MrimGroup group = new MrimGroup();
group.groupId = i;
group.name = name;
group.flags = flags;
//TODO use more flags
groups.add(group);
}
int i = 0;
while(pos < packet.rawData.length){
service.log("----- buddy -----");
int flags = (int)MrimEntityAdapter.ul2Long(packet.rawData, pos);
service.log("buddy flags " + flags);
pos+=4;
int groupId = (int)MrimEntityAdapter.ul2Long(packet.rawData, pos);
service.log("buddy group " + groupId);
pos+=4;
String uin = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos += (4 + MrimEntityAdapter.ul2Long(packet.rawData, pos));
service.log("buddy uin " + uin);
String name = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos += (4 + MrimEntityAdapter.ul2Long(packet.rawData, pos));
service.log("buddy name " + name);
int serverFlags = (int)MrimEntityAdapter.ul2Long(packet.rawData, pos);
service.log("buddy server flags " + serverFlags);
pos+=4;
int status = (int)MrimEntityAdapter.ul2Long(packet.rawData, pos);
service.log("buddy status " + status);
pos+=4;
String phone = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos += (4 + MrimEntityAdapter.ul2Long(packet.rawData, pos));
service.log("buddy phone " + phone);
String statusText = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos += (4 + MrimEntityAdapter.ul2Long(packet.rawData, pos));
service.log("buddy xstatus id " + statusText);
String xStatusTitle = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos += (4 + MrimEntityAdapter.ul2Long(packet.rawData, pos));
service.log("buddy xstatus title " + xStatusTitle);
String xStatusText = MrimEntityAdapter.lpsw2String(packet.rawData, pos);
pos += (4 + MrimEntityAdapter.ul2Long(packet.rawData, pos));
service.log("buddy xstatus text " + xStatusText);
long unknown = MrimEntityAdapter.ul2Long(packet.rawData, pos);
service.log("buddy unk " + unknown);
pos+=4;
String client = MrimEntityAdapter.lpsa2String(packet.rawData, pos);
pos += (4 + MrimEntityAdapter.ul2Long(packet.rawData, pos));
service.log("buddy uin " + uin + ", buddy name "+name);
pos += MrimEntityAdapter.skipFormatted(packet.rawData, contactMask, pos, 12);
if ((flags & MrimConstants.CONTACT_FLAG_REMOVED) != 0){
continue;
}
MrimBuddy buddy = new MrimBuddy();
buddy.id = i;
buddy.uin = uin;
buddy.groupId = groupId;
buddy.onlineInfo.xstatusName = xStatusTitle;
buddy.onlineInfo.xstatusText = xStatusText;
buddy.onlineInfo.status = status;
buddy.onlineInfo.xstatusId = statusText;
buddy.serverFlags = serverFlags;
buddy.flags = flags;
buddy.clientId = client;
buddy.name = name;
buddies.add(buddy);
i++;
}
service.getServiceResponse().respond(MrimServiceResponse.RES_CONNECTING, 9);
service.getServiceResponse().respond(MrimServiceResponse.RES_CLUPDATED, buddies, groups);
service.setCurrentState(MrimServiceInternal.STATE_CONNECTED);
service.startKeepalive();
service.getServiceResponse().respond(MrimServiceResponse.RES_CONNECTED);
service.getServiceResponse().respond(MrimServiceResponse.RES_ACCOUNTUPDATED, service.getOnlineInfo());
getIcon(service.getMrid());
}
private void parsePingFreq(MrimPacket packet) {
long pingFreq = MrimEntityAdapter.ul2Long(packet.rawData, 44);
service.setPingFrequency(pingFreq);
}
private void loginFailed(MrimPacket packet) {
service.lastConnectionError = MrimEntityAdapter.lpsa2String(packet.rawData, 44);
service.getRunnableService().disconnect();
}
private void reconnectBos(MrimBosString bos) {
service.setCurrentState(MrimServiceInternal.STATE_CONNECTING_BOS);
service.log("reconnect to " + bos.bosAddress + ":" + bos.bosPort);
service.getRunnableService().disconnect();
service.getServiceResponse().respond(MrimServiceResponse.RES_CONNECTING, 3);
service.setCurrentState(MrimServiceInternal.STATE_AUTHENTICATING);
service.runService(bos.bosAddress, bos.bosPort);
}
private void proceedLogin3() throws IOException {
service.log("logging in");
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_LOGIN3;
MD5 hash = new MD5();
hash.init();
hash.updateASCII(service.getPw());
hash.finish();
byte[] md5pw = hash.getDigestBits();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write(MrimEntityAdapter.string2lpsa(service.getMrid()));
stream.write(ProtocolUtils.int2ByteLE(md5pw.length));
stream.write(md5pw);
stream.write(ProtocolUtils.int2ByteLE(0x56));
stream.write(MrimEntityAdapter.string2lpsa(VERSION_INFO));
stream.write(MrimEntityAdapter.string2lpsa(LANG));
stream.write(ProtocolUtils.int2ByteLE(0x10));
stream.write(ProtocolUtils.int2ByteLE(0x1));
stream.write(MrimEntityAdapter.string2lpsa(GEO_LIST));
stream.write(MrimEntityAdapter.string2lpsa(ALIAS));
WeirdLoginEntity e2c = new WeirdLoginEntity();
e2c.type = 0x2c;
e2c.putBlob("00000134d148f68fab1ccbf13b4a2a05", "UTF-8");
stream.write(e2c.toByteArray());
WeirdLoginEntity e1 = new WeirdLoginEntity();
e1.type = 0x1;
e1.putBlob(new byte[]{0x4f, 0, 0, 0, 1});
e1.putBlob("176x208", "UTF-8");
//e1.putBlob("x", "UTF-8");
stream.write(e1.toByteArray());
WeirdLoginEntity e43 = new WeirdLoginEntity();
e43.type = 0x43;
e43.putBlob("RELEASE: "+Build.VERSION.RELEASE+";SDK_INT: "+Build.VERSION.SDK_INT, "UTF-16LE");
stream.write(e43.toByteArray());
WeirdLoginEntity e44 = new WeirdLoginEntity();
e44.type = 0x44;
e44.putBlob("MANUFACTURER: BEREZKA;MODEL: 61tc-311d;PRODUCT: tv;", "UTF-16LE");
stream.write(e44.toByteArray());
WeirdLoginEntity e45 = new WeirdLoginEntity();
e45.type = 0x45;
e45.putBlob("en", "UTF-16LE");
stream.write(e45.toByteArray());
packet.rawData = stream.toByteArray();
service.getRunnableService().sendToSocket(packet);
}
/*private void proceedLogin3() throws IOException {
service.log("logging in");
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_LOGIN3;
MD5 hash = new MD5();
hash.init();
hash.updateASCII(service.getPw());
hash.finish();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write(MrimEntityAdapter.string2lpsa(service.getMrid()));
stream.write(hash.getDigestBits());
stream.write(ProtocolUtils.int2ByteLE(0xffffffff));
stream.write(MrimEntityAdapter.string2lpsa(VERSION_INFO));
stream.write(MrimEntityAdapter.string2lpsa(LANG));
stream.write(ProtocolUtils.int2ByteLE(0x10));
stream.write(ProtocolUtils.int2ByteLE(0x1));
stream.write(MrimEntityAdapter.string2lpsa(GEO_LIST));
stream.write(MrimEntityAdapter.string2lpsa(ALIAS));
for (int i = 0; i <= 0x7a; )
{
stream.write(i);
if (i == 9 || i == 0x1e || i == 0x2c || i == 0x42 || i == 0x43 || i == 0x44 || i == 0x45 ||
i == 0x4b || i == 0x4c || i == 0x68)
stream.write(ProtocolUtils.int2ByteLE(0x01000000));
else
stream.write(ProtocolUtils.int2ByteLE(0x02000000));
if (i == 0)
stream.write(ProtocolUtils.int2ByteLE(0x00000e66)); //revision of MAgent
else if (i == 1)
stream.write(ProtocolUtils.int2ByteLE(7)); //seems to be minor version of MAgent
else if (i == 2)
stream.write(ProtocolUtils.int2ByteLE(19));
else if (i == 3)
stream.write(ProtocolUtils.int2ByteLE(0x51ec0ee9));
else if (i == 4 || i == 6 || i == 7 || i == 0x2d || i == 0x2f || i == 0x3f || i == 0x40 || i == 0x47 ||
i == 0x4e)
stream.write(ProtocolUtils.int2ByteLE(1));
else if (i == 8)
stream.write(ProtocolUtils.int2ByteLE(2));
else if (i == 9)
stream.write(new byte[]{
0x16, 0x00, 0x00, 0x00, 0x59, 0x50, 0x43, 0x6a, 0x5c, 0x59, 0x58, 0x55, 0x78, 0x54, 0x5f, 0x40,
0x46, 0x18, 0x46, 0x40, 0x54, 0x5a, 0x44, 0x66, 0x59, 0x57});
else if (i == 0x14)
stream.write(ProtocolUtils.int2ByteLE(0x00000501));
else if (i == 0x2c)
stream.write(new byte[]{
0x30, 0x39, 0x64, 0x65, 0x63, 0x31, 0x61, 0x63, 0x65, 0x33, 0x61, 0x30, 0x36, 0x34, 0x62, 0x64,
0x34, 0x31, 0x30, 0x34, 0x36, 0x64, 0x35, 0x61, 0x39, 0x37, 0x61, 0x39, 0x34, 0x62, 0x37, 0x36});
else if (i == 0x41)
stream.write(ProtocolUtils.int2ByteLE(0x00000c6e));
else if (i == 0x42)
//Hardware characteristics
stream.write(new byte[]{
0x41, 0x00, 0x4d, 0x00, 0x44, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00,
0x6f, 0x00, 0x6d, 0x00, 0x28, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x29, 0x00, 0x20, 0x00, 0x49, 0x00,
0x49, 0x00, 0x20, 0x00, 0x58, 0x00, 0x32, 0x00, 0x20, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00,
0x20, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x72, 0x00});
else if (i == 0x43)
//System characteristics
stream.write(new byte[]{
0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00,
0x74, 0x00, 0x20, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00,
0x73, 0x00, 0x20, 0x00, 0x58, 0x00, 0x50, 0x00, 0x20, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00,
0x66, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00});
else if (i == 0x45)
stream.write(new byte[]{0x08, 0x00, 0x00, 0x00, 0x30, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00});
else if (i == 0x46)
stream.write(ProtocolUtils.int2ByteLE(0x00000027));
else if (i == 0x48)
stream.write(ProtocolUtils.int2ByteLE(0x00000500));
else if (i == 0x49)
stream.write(ProtocolUtils.int2ByteLE(0x00000400));
else if (i == 0x4a)
stream.write(ProtocolUtils.int2ByteLE(0x00000020));
else if (i == 0x4b)
//Graphic card characteristics
stream.write(new byte[]{
0x56, 0x00, 0x69, 0x00, 0x72, 0x00, 0x74, 0x00, 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x42, 0x00,
0x6f, 0x00, 0x78, 0x00, 0x20, 0x00, 0x47, 0x00, 0x72, 0x00, 0x61, 0x00, 0x70, 0x00, 0x68, 0x00,
0x69, 0x00, 0x63, 0x00, 0x73, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00,
0x74, 0x00, 0x65, 0x00, 0x72, 0x00});
else if (i == 0x4c)
stream.write(new byte[]{0x69, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x47, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x48, 0x00});
else if (i == 0x4d)
stream.write(ProtocolUtils.int2ByteLE(0x000001ff));
else
stream.write(ProtocolUtils.int2ByteLE(0));
if (i == 3 || i == 4 || i == 0x1a || i == 0x13 || i == 0x14 || i == 0x54 || i == 0x66)
i += 2;
else if (i == 5)
i--;
else if (i == 0x15)
i = 0x67;
else if (i == 0x67)
i = 0x14;
else if (i == 0x2f)
i = 0x3f;
else
i++;
}
packet.rawData = stream.toByteArray();
service.getRunnableService().sendToSocket(packet);
}*/
@SuppressWarnings("unused")
private void proceedLogin() {
service.log("logging in");
MrimPacket packet = new MrimPacket();
MD5 hash = new MD5();
hash.init();
hash.updateASCII(service.getPw());
hash.finish();
byte[] md5pass = hash.getDigestBits();
packet.type = MrimConstants.MRIM_CS_LOGIN2;
byte[] mrid = MrimEntityAdapter.string2lpsa(service.getMrid());
//byte[] pw = MrimEntityAdapter.string2lpsa(service.getPw());
byte[] alias = MrimEntityAdapter.string2lpsa(ALIAS);
byte[] verInfo = MrimEntityAdapter.string2lpsa(VERSION_INFO);
byte[] lang = MrimEntityAdapter.string2lpsa(LANG);
byte[] statusDataBlob = getStatusSetByteBlob(service.getOnlineInfo().status, service.getOnlineInfo().xstatusId, service.getOnlineInfo().xstatusName, service.getOnlineInfo().xstatusText);
byte[] raw = new byte[12 + mrid.length + md5pass.length + statusDataBlob.length + verInfo.length + lang.length + alias.length];
Arrays.fill(raw, (byte) 0);
int pos = 0;
System.arraycopy(mrid, 0, raw, pos, mrid.length);
pos += mrid.length;
System.arraycopy(ProtocolUtils.int2ByteLE(md5pass.length), 0, raw, pos, 4);
pos += 4;
System.arraycopy(md5pass, 0, raw, pos, md5pass.length);
pos += md5pass.length;
/*System.arraycopy(ProtocolUtils.int2ByteLE(service.getCurrentStatus()), 0, raw, pos, 4);
pos += 4;
System.arraycopy(txtStatus, 0, raw, pos, txtStatus.length);
pos += txtStatus.length;
System.arraycopy(xstatusName, 0, raw, pos, xstatusName.length);
pos += xstatusName.length;
System.arraycopy(xstatusText, 0, raw, pos, xstatusText.length);
pos += xstatusText.length;
System.arraycopy(ProtocolUtils.int2ByteLE(0x12), 0, raw, pos, 4);
pos += 4;*/
System.arraycopy(statusDataBlob, 0, raw, pos, statusDataBlob.length);
pos+=statusDataBlob.length;
System.arraycopy(verInfo, 0, raw, pos, verInfo.length);
pos += verInfo.length;
System.arraycopy(lang, 0, raw, pos, lang.length);
pos += lang.length;
//skip two integers = 0
pos += 8;
System.arraycopy(alias, 0, raw, pos, alias.length);
pos += alias.length;
packet.rawData = raw;
service.getRunnableService().sendToSocket(packet);
}
private MrimPacket parseBosString(byte[] tail) throws MrimException {
MrimBosString bos = new MrimBosString();
String fullBos = new String(tail);
if (fullBos.length() < 1) {
throw new MrimException("Corrupted BOS address");
}
if (fullBos.indexOf(":") > -1) {
String[] boss = fullBos.split(":");
bos.bosAddress = boss[0];
bos.bosPort = Integer.parseInt(boss[1]);
} else {
bos.bosAddress = fullBos;
}
bos.type = MrimConstants.MRIM_CS_HELLO;
return bos;
}
public byte[] packet2Bytes(MrimPacket packet) throws MrimException {
if (packet == null || packet.type == -1) {
throw new MrimException("Nothing to convert");
}
if (packet.rawData == null) {
packet.rawData = new byte[0];
}
byte[] out = new byte[44 + packet.rawData.length];
Arrays.fill(out, (byte) 0);
System.arraycopy(ProtocolUtils.int2ByteLE(MrimConstants.CS_MAGIC), 0, out, 0, 4);
System.arraycopy(ProtocolUtils.int2ByteLE(MrimConstants.PROTO_VERSION), 0, out, 4, 4);
System.arraycopy(ProtocolUtils.int2ByteLE((int) packet.seqNumber), 0, out, 8, 4);
System.arraycopy(ProtocolUtils.int2ByteLE((int) packet.type), 0, out, 12, 4);
System.arraycopy(ProtocolUtils.int2ByteLE(packet.rawData.length), 0, out, 16, 4);
// here IP data may be added
System.arraycopy(packet.rawData, 0, out, 44, packet.rawData.length);
return out;
}
public byte[] packets2Bytes(MrimPacket[] packets) throws MrimException {
if (packets == null) {
throw new MrimException("Error - packets is null");
}
if (packets.length == 1) {
return packet2Bytes(packets[0]);
}
int length = 0;
List<byte[]> bytes = new ArrayList<byte[]>();
for (int i = 0; i < packets.length; i++) {
if (packets[i] == null) {
continue;
}
byte[] out = packet2Bytes(packets[i]);
length += out.length;
bytes.add(out);
}
byte[] out = new byte[length];
int pos = 0;
for (int i = 0; i < bytes.size(); i++) {
System.arraycopy(bytes.get(i), 0, out, pos, bytes.get(i).length);
pos += bytes.get(i).length;
}
return out;
}
public void sendHello() {
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_HELLO;
packet.rawData = new byte[0];
service.getRunnableService().sendToSocket(packet);
}
public void sendKeepalive() {
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_PING;
packet.rawData = new byte[0];
service.getRunnableService().sendToSocket(packet);
}
public void sendMessage(MrimMessage message) {
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_MESSAGE;
byte[] toBytes = MrimEntityAdapter.string2lpsa(message.to);
byte[] textBytes = MrimEntityAdapter.string2lpsw(message.text);
byte[] rtfBytes = MrimEntityAdapter.string2lpsa("");
byte[] data = new byte[toBytes.length+textBytes.length+rtfBytes.length+4];
int pos = 0;
System.arraycopy(ProtocolUtils.int2ByteLE(message.flags), 0, data, pos, 4);
pos+=4;
System.arraycopy(toBytes, 0, data, pos, toBytes.length);
pos+=toBytes.length;
System.arraycopy(textBytes, 0, data, pos, textBytes.length);
pos+=textBytes.length;
System.arraycopy(rtfBytes, 0, data, pos, rtfBytes.length);
pos+=rtfBytes.length;
packet.rawData = data;
long messageId = service.getRunnableService().sendToSocket(packet);
MessageData mdata = new MessageData();
mdata.email = message.to;
mdata.id = message.messageId;
msgIDs.put(messageId, mdata);
}
public void getIcon(final String email) {
new Thread(){
@Override
public void run(){
String[] items = email.split("@");
String[] domains = items[1].split("\\.");
String url = String.format(ICON_SERVER, domains[0], items[0]);
try {
HttpClient hc = new DefaultHttpClient();
HttpHead head = new HttpHead(url);
HttpResponse response = hc.execute(head);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND){
return;
}
HttpGet get = new HttpGet(url);
response = hc.execute(get);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//int len = (int) response.getEntity().getContentLength();
//if (len > 0){
byte[] bytes = new byte[1024];
int read = 0;
InputStream content = response.getEntity().getContent();
while (read > -1){
read = content.read(bytes, 0, 1024);
if (read > 0){
bos.write(bytes, 0, read);
}
};
//}
service.getServiceResponse().respond(MrimServiceResponse.RES_SAVEIMAGEFILE, bos.toByteArray(), email, new String(email.hashCode()+""));
} catch (Exception e) {
service.log(url+"\n");
service.log(e);
}
}
}.start();
}
private class MessageData implements Serializable {
/**
*
*/
private static final long serialVersionUID = -5512618917441817714L;
public int id = 0;
private String email;
}
public void setStatus(MrimOnlineInfo info) {
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_CHANGE_STATUS;
packet.rawData = getStatusSetByteBlob(info.status, info.xstatusId, info.xstatusName, info.xstatusText);
service.getRunnableService().sendToSocket(packet);
}
public byte[] getStatusSetByteBlob(int status, String xstatusName, String xstatusTitle, String xstatusText){
byte[] xstNameBytes = MrimEntityAdapter.string2lpsa(xstatusName);
byte[] xstTitleBytes = MrimEntityAdapter.string2lpsw(xstatusTitle);
byte[] xstTextBytes = MrimEntityAdapter.string2lpsw(xstatusText);
byte[] bytes = new byte[8+xstNameBytes.length+xstTextBytes.length+xstTitleBytes.length];
int pos=0;
System.arraycopy(ProtocolUtils.int2ByteLE(status), 0, bytes, pos, 4);
pos+=4;
System.arraycopy(xstNameBytes, 0, bytes, pos, xstNameBytes.length);
pos+=xstNameBytes.length;
System.arraycopy(xstTitleBytes, 0, bytes, pos, xstTitleBytes.length);
pos+=xstTitleBytes.length;
System.arraycopy(xstTextBytes, 0, bytes, pos, xstTextBytes.length);
pos+=xstTextBytes.length;
System.arraycopy(ProtocolUtils.int2ByteLE(0x56), 0, bytes, pos, 4);
pos += 4;
return bytes;
}
public void sendTyping(String uid) {
MrimMessage message = new MrimMessage();
message.to = uid;
message.text = " ";
message.flags = MrimConstants.MESSAGE_FLAG_NOTIFY;
//lazy filling in;
message.messageId = VERSION_INFO.hashCode();
sendMessage(message);
}
public void askForWebAuthKey() {
MrimPacket packet = new MrimPacket();
packet.type = MrimConstants.MRIM_CS_GET_MPOP_SESSION;
service.getRunnableService().sendToSocket(packet);
}
private class WeirdLoginEntity implements Serializable {
private static final long serialVersionUID = -5484794243398170724L;
public int type;
public final List<byte[]> blobs = new LinkedList<byte[]>();
public byte[] toByteArray() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
os.write(ProtocolUtils.int2ByteLE(type));
os.write(blobs.size());
for (byte[] blob : blobs){
os.write(blob);
}
return os.toByteArray();
}
public void putBlob(byte[] bt){
byte[] blob = new byte[4+bt.length];
System.arraycopy(ProtocolUtils.int2ByteLE(bt.length), 0, blob, 0, 4);
System.arraycopy(bt, 0, blob, 4, bt.length);
blobs.add(blob);
}
public void putBlob(String data, String encoding) {
byte[] strData;
try {
strData = data.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
strData = data.getBytes();
}
putBlob(strData);
}
}
}